#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _KEY_WORD_END "waiting for your expanding"
typedef struct
{
    int typenum;
    char * word;
} WORD;
char input[255];
char token[255]="";
int p_input;
int p_token;
char ch;
char * rwtab[]= {"begin","if","then","while","do","end",_KEY_WORD_END};
WORD* scaner();
int noteFlag = 0;
int nextLine = 1;
int syn;
int kk = 0;
WORD* oneword;

int main()
{
    int over=1;
    oneword=(WORD*)malloc(sizeof(WORD));
    FILE *fp = fopen("input.txt","r");
    if(fp==NULL)
    {
        printf("FAIL");
        exit(1);
    }
    fscanf(fp,"%[^EOF]",input);

    p_input=0;
    printf("YOUR WORDS:\n\n%s\n\n",input);
    printf("语法分析结果如下：\n");
    Irparser();
}
char m_getch()
{
    ch=input[p_input];
    p_input=p_input+1;
    return(ch);
}

void getbc()
{
    while(ch==' '||ch==10)
    {
        if(ch==10)
        {
            nextLine++;
        }
        ch=input[p_input];
        p_input=p_input+1;
    }
}
void concat()
{
    token[p_token]=ch;
    p_token=p_token+1;
    token[p_token]='\0';
}
int letter()
{
    if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
        return 1;
    else
        return 0;
}

int digit()
{
    if(ch>='0'&&ch<='9')
        return 1;
    else
        return 0;
}

int reserve()
{
    int i=0;
    while(strcmp(rwtab[i],_KEY_WORD_END))
    {
        if(!strcmp(rwtab[i],token))
        {
            return i+1;
        }
        i=i+1;
    }
    return 10;
}

void retract()
{
    p_input=p_input-1;

}
char*dtb()
{
    return NULL;
}

void getNext()
{
    while(syn!=26)
    {
        oneword = scaner();
        syn=oneword->typenum;
        if(syn==0){
        printf("Line %d:",nextLine);
        printf("È±*/´íÎó!\n");
        }
    }
}

void getNext1()
{
    while(syn!=38)
    {
        oneword = scaner();
        syn=oneword->typenum;
    }
}

WORD *scaner()
{
    WORD*myword=(WORD*)malloc(sizeof(WORD));
    myword->typenum=10;
    myword->word="";
    p_token=0;
    m_getch();
    getbc();
    if(noteFlag)
    {
        char ch1 = ch;
        m_getch();
        char ch2 = ch;
        while(ch1!='*'||ch2!='/')
        {
            ch = ch1;
            concat();
            ch1=ch2;
            m_getch();
            ch2=ch;
            if(ch2='#'){
                break;
            }
        }
        retract();
        retract();
        myword->typenum=36;
        myword->word=token;
        noteFlag=0;
        return(myword);
    }
    else if(letter())
    {
        while(letter()||digit())
        {
            concat();
            m_getch();
        }
        retract();
        myword->typenum=reserve();
        myword->word=token;
        return(myword);
    }
    else if(digit())
    {
        while(digit())
        {
            concat();
            m_getch();
        }
        retract();
        myword->typenum=11;
        myword->word=token;
        return (myword);
    }
    else
        switch(ch)
        {
        case'=':
            m_getch();
            if(ch=='=')
            {
                myword->typenum=29;
                myword->word="==";
                return(myword);

            }
            retract();
            myword->typenum=25;
            myword->word="=";
            return (myword);
            break;

        case '+':
            myword->typenum=13;
            myword->word="+";
            return (myword);
            break;
        case '-':
            myword->typenum=14;
            myword->word="-";
            return (myword);
            break;
        case '*':
            m_getch();
            if(ch=='/')
            {
                noteFlag=0;
                myword->typenum=38;
                myword->word="*/";
                return (myword);
            }
            retract();
            myword->typenum=15;
            myword->word="*";
            return (myword);
            break;
        case '/':
            m_getch();
            if(ch=='*')
            {
                noteFlag=1;
                myword->typenum=37;
                myword->word="/*";
                return (myword);
            }
            retract();
            myword->typenum=16;
            myword->word="/";
            return (myword);
            break;
        case '(':
            myword->typenum=27;
            myword->word="(";
            return (myword);
            break;
        case ')':
            myword->typenum=28;
            myword->word=")";
            return (myword);
            break;
        case '[':
            myword->typenum=30;
            myword->word="[";
            return (myword);
            break;
        case ']':
            myword->typenum=31;
            myword->word="]";
            return (myword);
            break;
        case '{':
            myword->typenum=32;
            myword->word="{";
            return (myword);
            break;
        case '}':
            myword->typenum=33;
            myword->word="}";
            return (myword);
            break;
        case '#':
            myword->typenum=0;
            myword->word="#";
            return (myword);
            break;
        case ',':
            myword->typenum=34;
            myword->word=",";
            return (myword);
            break;
        case ':':
            m_getch();
            if(ch=='=')
            {
                myword->typenum=18;
                myword->word=":=";
                return(myword);
            }
            retract();
            myword->typenum=17;
            myword->word=":";
            return (myword);
            break;
        case ';':
            myword->typenum=26;
            myword->word=";";
            return (myword);
            break;
        case'>':
            m_getch();
            if(ch=='=')
            {
                myword->typenum=24;
                myword->word=">=";
                return(myword);
            }
            retract();
            myword->typenum=23;
            myword->word=">";
            return (myword);
            break;
        case'<':
            m_getch();
            if(ch=='=')
            {
                myword->typenum=22;
                myword->word="<=";
                return(myword);
            }
            if(ch=='>')
            {
                myword->typenum=21;
                myword->word="<>";
                return(myword);
            }
            retract();
            myword->typenum=20;
            myword->word="<";
            return (myword);
            break;
        case'!':
            m_getch();
            if(ch=='=')
            {
                myword->typenum=35;
                myword->word="!=";
                return(myword);
            }
            retract();
            myword->typenum=-1;
            myword->word="ERROR";
            return (myword);
            break;
        case'|':
            m_getch();
            if(ch=='|')
            {
                myword->typenum=39;
                myword->word="||";
                return(myword);
            }
            retract();
            myword->typenum=-1;
            myword->word="ERROR";
            return (myword);
            break;
        case'&':
            m_getch();
            if(ch=='&')
            {
                myword->typenum=40;
                myword->word="&&";
                return(myword);
            }
            retract();
            myword->typenum=-1;
            myword->word="ERROR";
            return (myword);
            break;
        case'\0':
            myword->typenum=1000;
            myword->word="OVER";
            return(myword);
            break;
        default :
            myword->typenum=-1;
            myword->word="ERROR";
            return(myword);
        }
}

void Irparser()
{
    oneword = scaner();
    syn=oneword->typenum;
    if(syn!=1)
    {
        printf("Line %d:",nextLine);
        printf("È±begin´íÎó!\n");
        kk=1;
    }
    else
    {
        oneword = scaner();
        syn=oneword->typenum;
    }
    yucu();
    if(syn==6)
    {
        oneword = scaner();
        syn=oneword->typenum;
        if(syn==0&&(kk==0))
        {
            printf("success");
        }
    }
    else
    {
        printf("Line %d:",nextLine);
        printf("È±end´íÎó!\n");
    }
}

void yucu()
{
    statement();
    /* ; */
    while(syn==26)
    {
        oneword = scaner();
        syn=oneword->typenum;
        statement();
        if(syn==28)
        {
            printf("Line %d:",nextLine);
            printf("È±(´íÎó!\n");
            kk=1;
            getNext();
        }
    }
    return;
}

void statement()
{
    if(syn==10)
    {
        oneword = scaner();
        syn=oneword->typenum;
        if(syn==18)
        {
            oneword = scaner();
            syn=oneword->typenum;
            expression();
        }
        else
        {
            printf("Line %d:",nextLine);
            printf("¸³ÖµºÅ´íÎó£¡\n");
            kk=1;
            getNext();
        }
    }
    else if(syn==37)
    {
        getNext1();
        oneword = scaner();
        syn=oneword->typenum;
        statement();
    }
    else
    {
        printf("Line %d:",nextLine);
        printf("Óï¾ä´íÎó£¡\n");
        kk=1;
        getNext();
    }
    return;
}

void expression()
{
    term();
    while(syn==13||syn==14)
    {
        oneword = scaner();
        syn=oneword->typenum;
        term();
    }
    return;
}

void term()
{
    factor();
    while(syn==15||syn==16)
    {
        oneword = scaner();
        syn=oneword->typenum;
        factor();
    }
    return;
}

void factor()
{
    if(syn==10||syn==11)
    {
        oneword = scaner();
        syn=oneword->typenum;
    }
    else if(syn==27)
    {
        oneword = scaner();
        syn=oneword->typenum;
        expression();
        if(syn==28)
        {
            oneword = scaner();
            syn=oneword->typenum;
        }
        else
        {
            printf("Line %d:",nextLine);
            printf("È±)´íÎó!\n");
            kk=1;
            getNext();
        }
    }
    else
    {
        printf("Line %d:",nextLine);
        printf("±í´ïÊ½´íÎó!\n");
        kk=1;
        getNext();
    }
    return;
}

